<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>文件上传测试页面</title>
    <script src="https://cdn.jsdelivr.net/npm/axios@1.11.0/dist/axios.min.js"></script>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }

      body {
        font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        min-height: 100vh;
        padding: 20px;
      }

      .container {
        max-width: 800px;
        margin: 0 auto;
        background: white;
        border-radius: 15px;
        box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
        overflow: hidden;
      }

      .header {
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        color: white;
        padding: 30px;
        text-align: center;
      }

      .header h1 {
        font-size: 2.5em;
        margin-bottom: 10px;
        font-weight: 300;
      }

      .header p {
        opacity: 0.9;
        font-size: 1.1em;
      }

      .content {
        padding: 40px;
      }

      .upload-section {
        margin-bottom: 40px;
      }

      .section-title {
        font-size: 1.5em;
        color: #333;
        margin-bottom: 20px;
        border-bottom: 2px solid #667eea;
        padding-bottom: 10px;
      }

      .file-input-container {
        position: relative;
        margin-bottom: 20px;
      }

      .file-input {
        display: none;
      }

      .file-input-label {
        display: inline-block;
        padding: 15px 30px;
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        color: white;
        border-radius: 8px;
        cursor: pointer;
        transition: all 0.3s ease;
        font-size: 1.1em;
        border: none;
      }

      .file-input-label:hover {
        transform: translateY(-2px);
        box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
      }

      .selected-files {
        margin-top: 15px;
        padding: 15px;
        background: #f8f9fa;
        border-radius: 8px;
        border-left: 4px solid #667eea;
      }

      .file-item {
        display: flex;
        justify-content: space-between;
        align-items: center;
        padding: 8px 0;
        border-bottom: 1px solid #dee2e6;
      }

      .file-item:last-child {
        border-bottom: none;
      }

      .file-info {
        flex: 1;
      }

      .file-name {
        font-weight: 500;
        color: #333;
      }

      .file-size {
        font-size: 0.9em;
        color: #666;
      }

      .upload-btn {
        background: linear-gradient(135deg, #28a745 0%, #20c997 100%);
        color: white;
        border: none;
        padding: 15px 30px;
        border-radius: 8px;
        cursor: pointer;
        font-size: 1.1em;
        transition: all 0.3s ease;
        margin-right: 10px;
      }

      .upload-btn:hover {
        transform: translateY(-2px);
        box-shadow: 0 5px 15px rgba(40, 167, 69, 0.4);
      }

      .upload-btn:disabled {
        background: #6c757d;
        cursor: not-allowed;
        transform: none;
        box-shadow: none;
      }

      .clear-btn {
        background: linear-gradient(135deg, #dc3545 0%, #fd7e14 100%);
        color: white;
        border: none;
        padding: 15px 30px;
        border-radius: 8px;
        cursor: pointer;
        font-size: 1.1em;
        transition: all 0.3s ease;
      }

      .clear-btn:hover {
        transform: translateY(-2px);
        box-shadow: 0 5px 15px rgba(220, 53, 69, 0.4);
      }

      .progress-container {
        margin: 20px 0;
        display: none;
      }

      .progress-bar {
        width: 100%;
        height: 8px;
        background: #e9ecef;
        border-radius: 4px;
        overflow: hidden;
      }

      .progress-fill {
        height: 100%;
        background: linear-gradient(135deg, #28a745 0%, #20c997 100%);
        width: 0%;
        transition: width 0.3s ease;
      }

      .progress-text {
        text-align: center;
        margin-top: 10px;
        font-weight: 500;
        color: #495057;
      }

      .result {
        margin-top: 20px;
        padding: 20px;
        border-radius: 8px;
        display: none;
      }

      .result.success {
        background: #d4edda;
        border: 1px solid #c3e6cb;
        color: #155724;
      }

      .result.error {
        background: #f8d7da;
        border: 1px solid #f5c6cb;
        color: #721c24;
      }

      .files-list {
        margin-top: 40px;
      }

      .files-grid {
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
        gap: 20px;
        margin-top: 20px;
      }

      .file-card {
        background: #f8f9fa;
        border-radius: 8px;
        padding: 20px;
        border: 1px solid #dee2e6;
        transition: all 0.3s ease;
      }

      .file-card:hover {
        transform: translateY(-5px);
        box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
      }

      .file-card-name {
        font-weight: 500;
        color: #333;
        margin-bottom: 10px;
        word-break: break-all;
      }

      .file-card-meta {
        font-size: 0.9em;
        color: #666;
        margin-bottom: 15px;
      }

      .file-actions {
        display: flex;
        gap: 10px;
      }

      .btn-sm {
        padding: 8px 16px;
        border-radius: 6px;
        border: none;
        cursor: pointer;
        font-size: 0.9em;
        transition: all 0.3s ease;
      }

      .btn-download {
        background: #007bff;
        color: white;
      }

      .btn-download:hover {
        background: #0056b3;
      }

      .btn-delete {
        background: #dc3545;
        color: white;
      }

      .btn-delete:hover {
        background: #c82333;
      }

      .loading {
        display: inline-block;
        width: 20px;
        height: 20px;
        border: 2px solid #f3f3f3;
        border-top: 2px solid #667eea;
        border-radius: 50%;
        animation: spin 1s linear infinite;
        margin-right: 10px;
      }

      @keyframes spin {
        0% {
          transform: rotate(0deg);
        }
        100% {
          transform: rotate(360deg);
        }
      }

      .empty-state {
        text-align: center;
        padding: 40px;
        color: #666;
        font-size: 1.1em;
      }

      .api-info {
        background: #e7f3ff;
        border: 1px solid #b8daff;
        border-radius: 8px;
        padding: 20px;
        margin-bottom: 30px;
      }

      .api-info h3 {
        color: #0056b3;
        margin-bottom: 15px;
      }

      .api-endpoint {
        background: #fff;
        padding: 10px;
        border-radius: 4px;
        font-family: monospace;
        margin: 5px 0;
        border-left: 4px solid #0056b3;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <h1>文件上传测试</h1>
        <p>测试文件上传API功能，支持多文件上传，最大50MB</p>
      </div>

      <div class="content">
        <!-- API信息 -->
                   <div class="api-info">
             <h3>📋 API 接口信息</h3>
             <div class="api-endpoint">
               <strong>POST</strong> /api/upload - 上传文件（返回可访问的URL）
             </div>
             <div class="api-endpoint">
               <strong>GET</strong> /api/upload/list - 获取文件列表（包含访问URL）
             </div>
             <div class="api-endpoint">
               <strong>GET</strong> /uploads/:filename - 直接访问上传的文件
             </div>
             <div class="api-endpoint">
               <strong>GET</strong> /api/upload/download/:filename - 下载文件
             </div>
             <div class="api-endpoint">
               <strong>DELETE</strong> /api/upload/:filename - 删除文件
             </div>
           </div>

           <!-- 调试信息区域 -->
           <div id="debugInfo" class="api-info" style="background: #fff3cd; border-color: #ffeaa7;">
             <h3>🔧 调试信息 (苹果设备支持)</h3>
             <div id="deviceInfo" style="font-family: monospace; font-size: 0.9em;"></div>
             <button id="testConnBtn" class="upload-btn" style="margin-top: 10px; font-size: 0.9em; padding: 8px 16px;">
               🧪 测试连接
             </button>
           </div>

        <!-- 文件上传区域 -->
        <div class="upload-section">
          <h2 class="section-title">📁 选择文件</h2>

          <div class="file-input-container">
            <input type="file" id="fileInput" class="file-input" multiple />
            <label for="fileInput" class="file-input-label">
              📎 选择文件 (支持多选)
            </label>
          </div>

          <div id="selectedFiles" class="selected-files" style="display: none">
            <h4>已选择的文件：</h4>
            <div id="filesList"></div>
          </div>

          <div style="margin-top: 20px">
            <button id="uploadBtn" class="upload-btn" disabled>
              🚀 开始上传
            </button>
            <button id="clearBtn" class="clear-btn">🗑️ 清除选择</button>
          </div>

          <div id="progressContainer" class="progress-container">
            <div class="progress-bar">
              <div id="progressFill" class="progress-fill"></div>
            </div>
            <div id="progressText" class="progress-text">上传中...</div>
          </div>

          <div id="result" class="result"></div>
        </div>

        <!-- 已上传文件列表 -->
        <div class="files-list">
          <h2 class="section-title">📄 已上传文件</h2>
          <button
            id="refreshBtn"
            class="upload-btn"
            style="margin-bottom: 20px"
          >
            🔄 刷新列表
          </button>
          <div id="filesGrid" class="files-grid"></div>
        </div>
      </div>
    </div>

    <script>
      class FileUploader {
                 constructor() {
           this.fileInput = document.getElementById("fileInput");
           this.uploadBtn = document.getElementById("uploadBtn");
           this.clearBtn = document.getElementById("clearBtn");
           this.refreshBtn = document.getElementById("refreshBtn");
           this.selectedFiles = document.getElementById("selectedFiles");
           this.filesList = document.getElementById("filesList");
           this.progressContainer = document.getElementById("progressContainer");
           this.progressFill = document.getElementById("progressFill");
           this.progressText = document.getElementById("progressText");
           this.result = document.getElementById("result");
           this.filesGrid = document.getElementById("filesGrid");

           this.files = [];
           // 动态获取baseURL，支持不同设备访问
           this.baseURL = 'http://192.168.110.214:3000';

           // 检测浏览器类型，用于特殊处理
           this.isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
           this.isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent);
           this.isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;

           // 输出设备信息用于调试
           console.log('Device info:', {
             userAgent: navigator.userAgent,
             platform: navigator.platform,
             isSafari: this.isSafari,
             isIOS: this.isIOS,
             isMac: this.isMac,
             baseURL: this.baseURL
           });

           this.initEventListeners();
           this.initDebugInfo();
           this.loadFilesList();
         }

        initEventListeners() {
          this.fileInput.addEventListener("change", (e) =>
            this.handleFileSelect(e)
          );
          this.uploadBtn.addEventListener("click", () => this.uploadFiles());
          this.clearBtn.addEventListener("click", () => this.clearSelection());
          this.refreshBtn.addEventListener("click", () => this.loadFilesList());
        }

                 handleFileSelect(event) {
           try {
             console.log('File selection event:', event);
             
             this.files = Array.from(event.target.files);
             
             // Safari特殊处理：验证文件对象
             if (this.isSafari || this.isIOS) {
               this.files = this.files.filter(file => {
                 if (!file || !file.name) {
                   console.warn('Invalid file object detected (Safari):', file);
                   return false;
                 }
                 return true;
               });
             }
             
             console.log('Selected files:', this.files.map(f => ({
               name: f.name,
               size: f.size,
               type: f.type,
               lastModified: f.lastModified
             })));
             
             this.updateFilesList();
             this.uploadBtn.disabled = this.files.length === 0;
             
             if (this.files.length === 0 && event.target.files.length > 0) {
               this.showResult(false, '❌ 文件选择失败，请重试或尝试选择其他文件');
             }
           } catch (error) {
             console.error('File selection error:', error);
             this.showResult(false, '❌ 文件选择出错: ' + error.message);
           }
         }

        updateFilesList() {
          if (this.files.length === 0) {
            this.selectedFiles.style.display = "none";
            return;
          }

          this.selectedFiles.style.display = "block";
          this.filesList.innerHTML = "";

          this.files.forEach((file, index) => {
            const fileItem = document.createElement("div");
            fileItem.className = "file-item";
            fileItem.innerHTML = `
                        <div class="file-info">
                            <div class="file-name">${file.name}</div>
                            <div class="file-size">${this.formatFileSize(
                              file.size
                            )}</div>
                        </div>
                    `;
            this.filesList.appendChild(fileItem);
          });
        }

        formatFileSize(bytes) {
          if (bytes === 0) return "0 Bytes";
          const k = 1024;
          const sizes = ["Bytes", "KB", "MB", "GB"];
          const i = Math.floor(Math.log(bytes) / Math.log(k));
          return (
            parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i]
          );
        }

        formatDate(dateString) {
          const date = new Date(dateString);
          return date.toLocaleString("zh-CN");
        }

        async uploadFiles() {
          if (this.files.length === 0) return;

          const formData = new FormData();
          console.log('files', this.files);
          this.files.forEach((file) => {
            formData.append("files", file);
          });

          this.uploadBtn.disabled = true;
          this.progressContainer.style.display = "block";
          this.result.style.display = "none";

                     try {
             const response = await axios.post(
               `${this.baseURL}/api/upload`,
               formData,
               {
                 headers: {
                   "Content-Type": "multipart/form-data",
                 },
                 onUploadProgress: (progressEvent) => {
                   if (progressEvent.total > 0) {
                     const percentCompleted = Math.round(
                       (progressEvent.loaded * 100) / progressEvent.total
                     );
                     this.progressFill.style.width = percentCompleted + "%";
                     this.progressText.textContent = `上传进度: ${percentCompleted}%`;
                   }
                 },
                 timeout: 300000, // 5分钟超时，适应大文件上传
                 withCredentials: false // Safari兼容性
               }
             );

            // 构建包含URL的成功消息
            let successMessage = `✅ 成功上传 ${response.data.files.length} 个文件！\n\n📎 访问链接：`;
            response.data.files.forEach((file) => {
              successMessage += `\n• ${file.originalName}: ${this.baseURL}${file.url}`;
            });

            this.showResult(true, successMessage);
            this.clearSelection();
            this.loadFilesList();
                     } catch (error) {
             console.error("Upload error:", error);
             
             // 详细的错误日志，便于调试苹果设备问题
             console.log("Error details:", {
               message: error.message,
               code: error.code,
               response: error.response ? {
                 status: error.response.status,
                 statusText: error.response.statusText,
                 data: error.response.data
               } : null,
               request: error.request ? "Request made but no response" : null,
               userAgent: navigator.userAgent,
               platform: navigator.platform
             });
             
             let errorMessage = "❌ 上传失败";
             
             // 针对不同错误类型提供更友好的提示
             if (error.code === 'ECONNABORTED') {
               errorMessage += ": 上传超时，请检查网络连接或文件大小";
             } else if (error.code === 'ERR_NETWORK') {
               errorMessage += ": 网络连接失败，请检查网络设置";
             } else if (error.response) {
               if (error.response.status === 413) {
                 errorMessage += ": 文件太大，请选择小于50MB的文件";
               } else if (error.response.status === 0) {
                 errorMessage += ": 跨域问题，请检查服务器CORS配置";
               } else if (error.response.data && error.response.data.message) {
                 errorMessage += ": " + error.response.data.message;
               } else {
                 errorMessage += `: 服务器错误 (${error.response.status})`;
               }
             } else if (error.request) {
               errorMessage += ": 无法连接到服务器，请检查服务器是否运行";
             } else {
               errorMessage += ": " + error.message;
             }
             
             this.showResult(false, errorMessage);
          } finally {
            this.uploadBtn.disabled = false;
            this.progressContainer.style.display = "none";
          }
        }

        clearSelection() {
          this.files = [];
          this.fileInput.value = "";
          this.updateFilesList();
          this.uploadBtn.disabled = true;
          this.result.style.display = "none";
        }

        showResult(success, message) {
          this.result.className = success ? "result success" : "result error";
          // 处理换行符
          this.result.innerHTML = message.replace(/\n/g, "<br>");
          this.result.style.display = "block";

          setTimeout(() => {
            this.result.style.display = "none";
          }, 8000); // 延长显示时间以便查看URL
        }

        async loadFilesList() {
          this.refreshBtn.disabled = true;
          this.refreshBtn.innerHTML = '<div class="loading"></div>加载中...';

          try {
            const response = await axios.get(`${this.baseURL}/api/upload/list`);
            this.renderFilesList(response.data.files);
          } catch (error) {
            console.error("Load files error:", error);
            this.filesGrid.innerHTML =
              '<div class="empty-state">❌ 加载文件列表失败</div>';
          } finally {
            this.refreshBtn.disabled = false;
            this.refreshBtn.innerHTML = "🔄 刷新列表";
          }
        }

        renderFilesList(files) {
          if (!files || files.length === 0) {
            this.filesGrid.innerHTML =
              '<div class="empty-state">📂 暂无上传的文件</div>';
            return;
          }

          this.filesGrid.innerHTML = "";
          files.forEach((file) => {
            const fileCard = document.createElement("div");
            fileCard.className = "file-card";
            fileCard.innerHTML = `
                         <div class="file-card-name">📄 ${file.name}</div>
                         <div class="file-card-meta">
                             <div>大小: ${this.formatFileSize(file.size)}</div>
                             <div>上传时间: ${this.formatDate(
                               file.uploadTime
                             )}</div>
                             ${
                               file.url
                                 ? `<div>访问链接: <a href="${this.baseURL}${file.url}" target="_blank" style="color: #667eea; text-decoration: none;">🔗 ${file.url}</a></div>`
                                 : ""
                             }
                         </div>
                         <div class="file-actions">
                             <button class="btn-sm btn-download" onclick="fileUploader.downloadFile('${
                               file.name
                             }')">
                                 ⬇️ 下载
                             </button>
                             ${
                               file.url
                                 ? `<button class="btn-sm" style="background: #667eea; color: white;" onclick="fileUploader.openFile('${file.url}')">👁️ 预览</button>`
                                 : ""
                             }
                             <button class="btn-sm btn-delete" onclick="fileUploader.deleteFile('${
                               file.name
                             }')">
                                 🗑️ 删除
                             </button>
                         </div>
                     `;
            this.filesGrid.appendChild(fileCard);
          });
        }

        async downloadFile(filename) {
          try {
            const link = document.createElement("a");
            link.href = `${
              this.baseURL
            }/api/upload/download/${encodeURIComponent(filename)}`;
            console.log("link.href", link.href);
            link.download = filename;
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
          } catch (error) {
            console.error("Download error:", error);
            alert("下载失败: " + error.message);
          }
        }

        async deleteFile(filename) {
          if (!confirm(`确定要删除文件 "${filename}" 吗？`)) {
            return;
          }

          try {
            await axios.delete(
              `${this.baseURL}/api/upload/${encodeURIComponent(filename)}`
            );
            this.showResult(true, `✅ 文件 "${filename}" 删除成功！`);
            this.loadFilesList();
          } catch (error) {
            console.error("Delete error:", error);
            let errorMessage = `❌ 删除文件 "${filename}" 失败`;
            if (
              error.response &&
              error.response.data &&
              error.response.data.message
            ) {
              errorMessage += ": " + error.response.data.message;
            }
            this.showResult(false, errorMessage);
          }
        }

                 openFile(url) {
           window.open(`${this.baseURL}${url}`, "_blank");
         }

         initDebugInfo() {
           const deviceInfo = document.getElementById('deviceInfo');
           const testConnBtn = document.getElementById('testConnBtn');
           
           // 显示设备信息
           deviceInfo.innerHTML = `
             <div><strong>浏览器:</strong> ${navigator.userAgent}</div>
             <div><strong>平台:</strong> ${navigator.platform}</div>
             <div><strong>语言:</strong> ${navigator.language}</div>
             <div><strong>Safari:</strong> ${this.isSafari ? '是' : '否'}</div>
             <div><strong>iOS:</strong> ${this.isIOS ? '是' : '否'}</div>
             <div><strong>Mac:</strong> ${this.isMac ? '是' : '否'}</div>
             <div><strong>Base URL:</strong> ${this.baseURL}</div>
             <div><strong>当前时间:</strong> ${new Date().toLocaleString()}</div>
           `;
           
           // 绑定测试连接按钮
           testConnBtn.addEventListener('click', () => this.testConnection());
         }

         async testConnection() {
           const testConnBtn = document.getElementById('testConnBtn');
           const originalText = testConnBtn.innerHTML;
           
           testConnBtn.disabled = true;
           testConnBtn.innerHTML = '<div class="loading"></div>测试中...';
           
           try {
             console.log('开始连接测试...');
             
             // 测试基本连接
             const response = await axios.get(`${this.baseURL}/`, {
               timeout: 10000,
               withCredentials: false
             });
             
             console.log('连接测试成功:', response);
             
             // 测试上传接口
             const uploadTestResponse = await axios.options(`${this.baseURL}/api/upload`, {
               timeout: 5000,
               withCredentials: false
             });
             
             console.log('上传接口预检成功:', uploadTestResponse);
             
             this.showResult(true, `✅ 连接测试成功！
               <br>• 服务器响应正常
               <br>• 上传接口可访问
               <br>• CORS配置正确`);
               
           } catch (error) {
             console.error('连接测试失败:', error);
             
             let errorMsg = '❌ 连接测试失败:<br>';
             if (error.code === 'ECONNABORTED') {
               errorMsg += '• 连接超时，请检查网络';
             } else if (error.response) {
               errorMsg += `• 服务器响应错误: ${error.response.status}`;
               if (error.response.status === 0) {
                 errorMsg += '<br>• 可能是CORS跨域问题';
               }
             } else if (error.request) {
               errorMsg += '• 无法连接到服务器<br>• 请确认服务器运行在: ' + this.baseURL;
             } else {
               errorMsg += '• ' + error.message;
             }
             
             this.showResult(false, errorMsg);
           } finally {
             testConnBtn.disabled = false;
             testConnBtn.innerHTML = originalText;
           }
         }
       }

       // 初始化文件上传器
       const fileUploader = new FileUploader();
    </script>
  </body>
</html>
